#include <iostream>
#include <stack>
#include <queue>
using namespace std;

const int maxn = 300;
int da[maxn][maxn];
int n, m;

struct coord
{
	int x;
	int y;
};

stack<coord> ans;
queue<coord> q;

const int op[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1}};

void insert_to_queue(int x, int y)
{
	coord tmp;
	tmp.x = x; tmp.y = y;
	q.push(tmp);
}

bool inrange(int x, int y)
{
	return ((0 <= x && x < n) && (0 <= y && y < m));
}

bool judge(coord c)
{
	ans.push(c);
	int x = c.x, y = c.y;
	da[x][y]--;
	for (int i = 0; i < 4; i++) {
		int px = x + op[i][0], py = y + op[i][1];
		if (inrange(px, py)) {
			if (da[px][py] == 1) return false;
			da[px][py]--;
			if (da[px][py] == 1) insert_to_queue(px, py);
		}
	}
	return true;
}

int main()
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	for (int i = 0; i < n; i++)
		for (int j =0; j < m; j++) cin >> da[i][j];

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (da[i][j] == 1) insert_to_queue(i, j);
	while (!q.empty()) {
		if (!judge(q.front())) {
			cout << "No solution" << endl;
			return 0;
		}
		q.pop();
	}
	if (ans.size() < n*m) {
		cout << "No solution" << endl;
		return 0;
	}
	while (!ans.empty()) {
		cout << ans.top().x + 1 << " " << ans.top().y + 1 << endl;
		ans.pop();
	}
}
